// 执行命令  ts-node Interfaces.ts
// 接口
// 在面向对象语言中，接口（Interfaces）是一个很重要的概念，它是对行为的抽象，而具体如何行动需要由类（classes）去实现（implement）。
// TypeScript 中的接口是一个非常灵活的概念，除了可用于[对类的一部分行为进行抽象]以外，也常用于对「对象的形状（Shape）」进行描述。
// 接口一般首字母大写

// 赋值的时候，变量的形状必须和接口的形状保持一致
interface Person {
  name: string;
  age: number;
}
let tomInter: Person = {
  name: 'Tom',
  age: 25,
  // height: 180
}


// 可选 | 只读属性
interface Person1 {
  readonly name: string;
  age?: number;
}
let tomInter1: Person1 = {
  name: '1'
}
// tomInter1.name = '2' // Error
let aInter: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = aInter;
// ro[0] = 12; // error!
// ro.push(5); // error!
// ro.length = 100; // error!
// aInter = ro; // error!


// 任意属性    一旦定义了任意属性，那么确定属性和可选属性的类型都必须是它的类型的子集
interface Person2 {
  age?: number;
  [propName: string]: string | number;
}
let tomInter2: Person2 = {
  age: 22,
  kk: 3
}


// 鸭式辨型法  通过制定规则来判定对象是否实现这个接口
interface LabeledValue {
  label: string;
}
function printLabel(labeledObj: LabeledValue) {
  console.log(labeledObj.label)
}
let myObj = { size: 10, label: 'size 10 Object' }
printLabel(myObj)
// printLabel({ size: 10, label: 'size 10 Object' }) // Error


// 绕开额外属性检查的方式
// 类型断言
interface Props {
  name: string;
  age: number;
  money?: number;
}
let p: Props = {
  name: 'name',
  age: 22,
  money: -200,
  gril: false
} as Props
// 索引签名
interface Props1 { 
  name: string; 
  age: number; 
  money?: number;
  [key: string]: any;
}

let p1: Props1 = {
  name: "兔神",
  age: 25,
  money: -100000,
  girl: false
} // OK



console.log('Interfaces: ', tomInter2)